'use client'

import React, { useRef, useEffect, useState, useCallback } from 'react'
import { toast } from 'sonner'
import * as THREE from 'three'
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js'
import AMapLoader from '@amap/amap-jsapi-loader'
import ReactDOM from 'react-dom/client'
import { config, AMAP_KEY } from '@/lib/config'
import { EmergencyEvent } from '@/lib/emergencyEvents'
import EmergencyMarker from './EmergencyMarker'


// 高德地图相关类型
declare global {
  interface Window {
    AMap: any
    Loca: any
  }
}

interface POIData {
  id: string
  name: string
  type: 'department' | 'equipment' | 'entrance' | 'elevator' | 'stairs' | 'toilet' | 'emergency' | 'user'
  position: [number, number] // 经纬度
  floor: string
  description?: string
  metadata?: Record<string, any>
}

// 用户位置数据类型
interface UserLocation {
  userId: string;
  username?: string;
  latitude: number;
  longitude: number;
  accuracy: number;
  timestamp: number;
  address?: string;
  floor?: string;
  department?: string;
  status: 'online' | 'offline';
  lastUpdate: string;
  deviceType?: 'wxapp' | 'mobile' | 'web';
  sessionId?: string;
}

// 位置请求数据类型
interface LocationRequest {
  id: string;
  userId: string;
  username?: string;
  type: 'navigation' | 'emergency' | 'appointment' | 'consultation';
  title: string;
  description: string;
  priority: 'low' | 'medium' | 'high' | 'critical';
  status: 'pending' | 'responding' | 'completed' | 'cancelled';
  timestamp: number;
  estimatedTime?: number;
}

interface StoreData {
  id: string
  name: string
  business: string
  lnglat: [number, number]
  metadata?: Record<string, any>
}

interface HospitalMapViewerProps {
  amapKey: string
  center?: [number, number] // 默认中心点经纬度
  zoom?: number
  svgModelUrl?: string // SVG模型文件URL
  pois?: POIData[] // POI点位数据
  onPOIClick?: (poi: POIData) => void
  onStoreClick?: (store: StoreData) => void
  onMapClick?: (lngLat: [number, number]) => void
  onModelClick?: (object: THREE.Object3D, point: THREE.Vector3) => void
  onEmergencyClick?: (emergency: EmergencyEvent) => void
  emergencies?: EmergencyEvent[] // 突发事件列表
  enableLocationMonitor?: boolean // 是否启用位置监控
  apiBaseUrl?: string // API基础URL
  onUserLocationClick?: (location: UserLocation) => void
  onLocationRequestClick?: (request: LocationRequest) => void
  className?: string
}

export interface HospitalMapViewerRef {
  addPOI: (poi: POIData) => void
  removePOI: (id: string) => void
  addStore: (store: StoreData) => void
  removeStore: (id: string) => void
  clearAllPOIs: () => void
  setFloorVisible: (floor: string, visible: boolean) => void
  flyTo: (lngLat: [number, number], zoom?: number) => boolean
  clearSelectedPOI: () => void
  clearHighlight: () => void
  loadModel: (url: string) => Promise<void>
  getMap: () => any
  getScene: () => THREE.Scene | null
  getCamera: () => THREE.PerspectiveCamera | undefined
  addEmergency: (emergency: EmergencyEvent) => void
  removeEmergency: (id: string) => void
  highlightEmergency: (id: string) => void
  // 位置监控相关方法
  addUserLocation: (location: UserLocation) => void
  removeUserLocation: (userId: string) => void
  getUserLocations: () => UserLocation[]
  getLocationRequests: () => LocationRequest[]
  updateRequestStatus: (requestId: string, status: string) => void
}

export const HospitalMapViewer = React.forwardRef<HospitalMapViewerRef, HospitalMapViewerProps>(({
  amapKey,
  center = [120.1551, 30.2741], // 默认杭州坐标
  zoom = 16,
  svgModelUrl,
  pois = [],
  onPOIClick,
  onStoreClick,
  onMapClick,
  onModelClick,
  onEmergencyClick,
  emergencies = [],
  enableLocationMonitor = false,
  apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || 'https://api.zhihunyun.xyz',
  onUserLocationClick,
  onLocationRequestClick,
  className = "w-full h-full"
}, ref) => {
  // Refs
  const containerRef = useRef<HTMLDivElement>(null)
  const AMapRef = useRef<any>(null)
  const mapRef = useRef<any>(null)
  const initOnceRef = useRef<boolean>(false)
  const locaRef = useRef<any>(null)
  const customCoordsRef = useRef<any>(null)
  const sceneRef = useRef<THREE.Scene>(new THREE.Scene())
  const cameraRef = useRef<THREE.PerspectiveCamera>()
  const rendererRef = useRef<THREE.WebGLRenderer>()
  const floorGroupRef = useRef<THREE.Group>(new THREE.Group())
  const floorGroupChildrenRef = useRef<THREE.Object3D[]>([])
  const hasCenteredOnLocationsRef = useRef<boolean>(false)
  const rayStateRef = useRef({
    raycaster: new THREE.Raycaster(),
    mouse: new THREE.Vector2()
  })

  // State
  const [mapLoaded, setMapLoaded] = useState(false)
  const [mapLoadFailed, setMapLoadFailed] = useState(false)
  const [loadError, setLoadError] = useState<string>('')
  const [modelLoaded, setModelLoaded] = useState(false)
  const [selectedPOI, setSelectedPOI] = useState<POIData | null>(null)
  const [internalPOIs, setInternalPOIs] = useState<POIData[]>([])
  const [stores, setStores] = useState<StoreData[]>([])
  const [activeEmergencies, setActiveEmergencies] = useState<EmergencyEvent[]>([])
  const [selectedEmergency, setSelectedEmergency] = useState<EmergencyEvent | null>(null)
  const [highlightMarker, setHighlightMarker] = useState<any>(null)
  const [highlightCircle, setHighlightCircle] = useState<any>(null)
  
  // 位置监控相关状态
  const [userLocations, setUserLocations] = useState<UserLocation[]>([])
  const [locationRequests, setLocationRequests] = useState<LocationRequest[]>([])
  const [isLocationConnected, setIsLocationConnected] = useState(false)

  // 用于存储已渲染的标记，避免重复渲染
  const markersRef = useRef<any[]>([])

  // 清除所有标记
  const clearAllMarkers = useCallback(() => {
    if (mapRef.current && markersRef.current.length > 0) {
      markersRef.current.forEach(marker => {
        try {
          mapRef.current.remove(marker)
        } catch (error) {
          console.warn('移除标记失败:', error)
        }
      })
      markersRef.current = []
    }
  }, [])

  // 处理外部传入的POI数据（仅在组件初始化时）
  useEffect(() => {
    // 只在组件挂载时设置初始POI数据
    if (pois && pois.length > 0 && internalPOIs.length === 0) {
      setInternalPOIs([...pois])
    }
  }, [pois]) // 移除 internalPOIs 避免无限循环

  // 渲染POI标记到地图
  useEffect(() => {
    if (!mapRef.current || !AMapRef.current || !mapLoaded) return

    // 清除现有标记
    clearAllMarkers()

    // 渲染新的POI标记
    if (internalPOIs.length > 0) {
      const newMarkers: any[] = []

      // 只渲染唯一的用户POI，避免同一用户重复
      const seenIds = new Set<string>()
      internalPOIs.forEach(poi => {
        if (poi.id.startsWith('user_')) {
          if (seenIds.has(poi.id)) return
          seenIds.add(poi.id)
        }
        try {
          if (!mapRef.current || !AMapRef.current) return

          const position = new AMapRef.current.LngLat(poi.lnglat?.[0] || poi.position[0], poi.lnglat?.[1] || poi.position[1])
          const element = document.createElement('div')
          const root = ReactDOM.createRoot(element)
          
          // 根据POI类型设置样式
          const isUserLocation = poi.type === 'user'
          const iconStyle = {
            width: isUserLocation ? 80 : 60,
            height: isUserLocation ? 50 : 40,
            background: isUserLocation ? '#10b981' : '#3b82f6',
            color: 'white',
            borderRadius: isUserLocation ? '25px' : '4px',
            padding: '4px 8px',
            fontSize: '12px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
            border: isUserLocation ? '3px solid #059669' : '2px solid white',
            cursor: 'pointer',
            position: 'relative' as const
          }

          const markerElement = document.createElement('div')
          Object.assign(markerElement.style, iconStyle)
          // 为用户位置添加额外的视觉效果
          if (isUserLocation) {
            markerElement.innerHTML = `
              <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 8px; height: 8px; background: #fff; border-radius: 50%; animation: pulse 2s infinite;"></div>
                <span>${poi.name}</span>
              </div>
            `
            
            // 添加脉冲动画
            const style = document.createElement('style')
            style.textContent = `
              @keyframes pulse {
                0%, 100% { opacity: 1; transform: scale(1); }
                50% { opacity: 0.5; transform: scale(1.2); }
              }
            `
            document.head.appendChild(style)
          } else {
            markerElement.textContent = poi.name
          }
          
          markerElement.onclick = () => {
            setSelectedPOI(poi)
            onPOIClick?.(poi)
            
            // 如果是用户位置，触发用户位置点击回调
            if (isUserLocation && poi.metadata?.isUserLocation && onUserLocationClick) {
              const userLocation = userLocations.find(loc => loc.userId === poi.metadata.userId)
              if (userLocation) {
                onUserLocationClick(userLocation)
              }
            }
          }

          const marker = new AMapRef.current.Marker({
            position: position,
            content: markerElement,
            offset: new AMapRef.current.Pixel(-30, -20),
          })

          mapRef.current.add(marker)
          newMarkers.push(marker)
        } catch (error) {
          console.warn('渲染POI标记失败:', poi.name, error)
        }
      })

      markersRef.current = newMarkers
      console.log(`已渲染 ${newMarkers.length} 个POI标记`)
    }
  }, [internalPOIs, mapLoaded, clearAllMarkers, onPOIClick])

  // 渲染商店标记到地图
  useEffect(() => {
    if (!mapRef.current || !AMapRef.current || !mapLoaded || stores.length === 0) return

    stores.forEach(store => {
      try {
        if (!mapRef.current || !AMapRef.current) return

        const position = new AMapRef.current.LngLat(store.lnglat?.[0] || store.position[0], store.lnglat?.[1] || store.position[1])

        // 直接创建商店标记组件
        const iconStyle = {
          width: 60,
          height: 40,
          background: '#10b981',
          color: 'white',
          borderRadius: '4px',
          padding: '4px 8px',
          fontSize: '12px',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
          border: '2px solid white',
          cursor: 'pointer'
        }

        const markerElement = document.createElement('div')
        Object.assign(markerElement.style, iconStyle)
        markerElement.innerHTML = `
          <div style="text-align: center;">
            <div>${store.name}</div>
            ${store.business ? `<div style="font-size: 10px; opacity: 0.8;">${store.business}</div>` : ''}
          </div>
        `
        markerElement.onclick = () => {
          onStoreClick?.(store)
        }

        const marker = new AMapRef.current.Marker({
          position: position,
          content: markerElement,
          offset: new AMapRef.current.Pixel(-30, -20),
        })

        mapRef.current.add(marker)
        markersRef.current.push(marker)
      } catch (error) {
        console.warn('渲染商店标记失败:', store.name, error)
      }
    })
  }, [stores, mapLoaded, onStoreClick])

  // 组件卸载时清理标记
  useEffect(() => {
    return () => {
      clearAllMarkers()
    }
  }, [clearAllMarkers])


  // 创建3D建筑高亮效果
  const createLocationHighlight = useCallback((center: [number, number]) => {
    if (!mapRef.current || !AMapRef.current) return

    try {
      // 清除之前的高亮效果
      clearLocationHighlight()

      console.log('创建3D建筑高亮:', center)

      // 查找目标位置周围的建筑物并高亮
      const targetPosition = new AMapRef.current.LngLat(center[0], center[1])

      // 安全检查AMap.Buildings是否可用
      if (!AMapRef.current.Buildings) {
        console.warn('AMap.Buildings 不可用，跳过建筑高亮')
        return
      }

      // 创建建筑物高亮样式 - 使用更大的搜索区域
      const buildings = new AMapRef.current.Buildings({
        zIndex: 220,
        zooms: [14, 20],
        heightFactor: 1.2 // 建筑高度系数，稍微增高一些以突出效果
      })

      // 计算医院区域的多边形范围（更精确的区域定位）
      const highlightArea = 0.002 // 约200米范围
      const hospitalPolygon = [
        [center[0] - highlightArea, center[1] - highlightArea], // 西南角
        [center[0] + highlightArea, center[1] - highlightArea], // 东南角
        [center[0] + highlightArea, center[1] + highlightArea], // 东北角
        [center[0] - highlightArea, center[1] + highlightArea], // 西北角
        [center[0] - highlightArea, center[1] - highlightArea]  // 闭合
      ]

      // 设置高亮样式
      buildings.setStyle({
        hideWithoutStyle: false,
        areas: [{
          visible: true,
          rejectTexture: true, // 屏蔽默认纹理，使用纯色
          color1: 'rgba(16, 185, 129, 0.8)', // 楼顶颜色 - 绿色高亮
          color2: 'rgba(5, 150, 105, 0.9)', // 楼面颜色 - 稍深的绿色
          path: hospitalPolygon
        }]
      })

      // 安全地添加到地图
      if (mapRef.current && typeof mapRef.current.add === 'function') {
        mapRef.current.add(buildings)
        setHighlightMarker(buildings) // 复用这个状态存储建筑高亮
      } else {
        console.warn('地图实例不支持add方法，跳过建筑高亮')
        return
      }

      // 创建一个脉冲光效标记
      const pulseMarker = new AMapRef.current.Marker({
        position: targetPosition,
        icon: new AMapRef.current.Icon({
          size: new AMapRef.current.Size(40, 40),
          image: 'data:image/svg+xml;base64,' + btoa(`
            <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
              <defs>
                <radialGradient id="buildingPulse" cx="50%" cy="50%" r="50%">
                  <stop offset="0%" style="stop-color:#10b981;stop-opacity:1"/>
                  <stop offset="100%" style="stop-color:#10b981;stop-opacity:0"/>
                </radialGradient>
              </defs>
              <circle cx="20" cy="20" r="15" fill="url(#buildingPulse)">
                <animate attributeName="r" values="8;18;8" dur="2s" repeatCount="indefinite"/>
                <animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/>
              </circle>
              <circle cx="20" cy="20" r="3" fill="#10b981" stroke="#ffffff" stroke-width="2"/>
            </svg>
          `),
          imageSize: new AMapRef.current.Size(40, 40)
        }),
        offset: new AMapRef.current.Pixel(-20, -20),
        zIndex: 1000
      })

      mapRef.current.add(pulseMarker)
      setHighlightCircle(pulseMarker) // 复用这个状态存储脉冲标记

      // 创建建筑高亮呼吸动画效果
      let opacity1 = 0.8 // 楼顶透明度
      let opacity2 = 0.9 // 楼面透明度

      let increasing = false

      const animateBuilding = () => {
        if (increasing) {
          opacity1 += 0.03
          opacity2 += 0.02
          if (opacity1 >= 0.95) increasing = false
        } else {
          opacity1 -= 0.03
          opacity2 -= 0.02
          if (opacity1 <= 0.4) increasing = true
        }

        // 限制透明度数值范围
        opacity1 = Math.max(0.4, Math.min(0.95, opacity1))
        opacity2 = Math.max(0.5, Math.min(1.0, opacity2))

        if (buildings && mapRef.current) {
          try {
            // 只更新建筑颜色样式（高度系数无法动态修改）
            buildings.setStyle({
              hideWithoutStyle: false,
              areas: [{
                visible: true,
                rejectTexture: true,
                color1: `rgba(16, 185, 129, ${opacity1})`, // 楼顶颜色
                color2: `rgba(5, 150, 105, ${opacity2})`, // 楼面颜色
                path: hospitalPolygon
              }]
            })
          } catch (e) {
            console.warn('更新建筑样式失败:', e)
            // 如果样式更新失败，停止动画避免持续错误
            if (animationInterval) {
              clearInterval(animationInterval)
            }
          }
        }
      }

      // 启动建筑呼吸动画（5秒后停止）
      const animationInterval = setInterval(animateBuilding, 100)
      setTimeout(() => {
        clearInterval(animationInterval)
        // 3秒后自动清除高亮效果
        setTimeout(() => {
          clearLocationHighlight()
        }, 2000)
      }, 5000)

      console.log('3D建筑高亮创建成功')
    } catch (error) {
      console.error('创建3D建筑高亮失败:', error)
    }
  }, [])

  // 清除位置高亮效果
  const clearLocationHighlight = useCallback(() => {
    if (highlightMarker && mapRef.current) {
      mapRef.current.remove(highlightMarker)
      setHighlightMarker(null)
    }
    if (highlightCircle && mapRef.current) {
      mapRef.current.remove(highlightCircle)
      setHighlightCircle(null)
    }
  }, [highlightMarker, highlightCircle])

  // 创建高德地图实例
  const CreateAMap = () => {
    return new Promise((resolve, reject) => {
      const mapKey = amapKey || AMAP_KEY

      // 检查API Key
      if (!mapKey) {
        const error = new Error('缺少高德地图API Key')
        console.error('地图初始化失败:', error)
        reject(error)
        return
      }

      // 如果已存在全局 AMap，直接复用，避免重复加载导致的假错误
      if (typeof window !== 'undefined' && (window as any).AMap && typeof (window as any).AMap.Map === 'function') {
        console.log('检测到全局已存在 AMap，跳过加载')
        resolve((window as any).AMap)
        return
      }

      console.log('正在加载高德地图SDK...', {
        key: mapKey.substring(0, 8) + '...',
        version: config.amap.version,
        plugins: config.amap.plugins
      })

      // 添加超时机制
      const loadTimeout = setTimeout(() => {
        reject(new Error('地图SDK加载超时，请检查网络连接'))
      }, 10000) // 10秒超时

      AMapLoader.load({
        "key": mapKey,
        "version": config.amap.version,
        "plugins": config.amap.plugins,
        "Loca": config.amap.loca,
      }).then(async (AMap) => {
        clearTimeout(loadTimeout)
        console.log('高德地图SDK加载成功:', AMap)

        // 验证AMap对象是否有效
        if (!AMap || typeof AMap.Map !== 'function') {
          throw new Error('高德地图SDK加载异常，Map构造函数不存在')
        }

        // 检查Loca是否可用
        if (!window.Loca || !window.Loca.Container) {
          console.warn('Loca 3D可视化库加载失败，将使用基础地图功能')
        }

        resolve(AMap)
      }).catch((error) => {
        clearTimeout(loadTimeout)
        // 若全局已存在AMap，则视为可用（可能是之前已加载成功），避免误报
        if (typeof window !== 'undefined' && (window as any).AMap && typeof (window as any).AMap.Map === 'function') {
          console.warn('高德地图SDK加载失败，但检测到全局已有 AMap，继续使用已有实例')
          resolve((window as any).AMap)
          return
        }

        console.error('高德地图SDK加载失败:', error)
        let errorMessage = '地图SDK加载失败'

        // 安全地检查错误信息
        const errMsg = error && error.message ? error.message : (error ? String(error) : '')

        if (errMsg.includes('key') || errMsg.includes('INVALID_USER_KEY')) {
          errorMessage = 'API Key无效或已过期，请检查配置'
        } else if (errMsg.includes('network') || errMsg.includes('timeout') || errMsg.includes('ENOTFOUND')) {
          errorMessage = '网络连接超时，请检查网络连接'
        } else if (errMsg.includes('quota') || errMsg.includes('DAILY_QUERY_OVER_LIMIT')) {
          errorMessage = 'API调用量已超限'
        } else if (error === undefined || error === null || errMsg === '') {
          errorMessage = '地图服务响应异常，可能是网络问题或服务不可用'
        } else {
          errorMessage = `SDK加载失败: ${errMsg}`
        }

        reject(new Error(errorMessage))
      })
    })
  }



  // 清除多余楼块
  const cleanBuild = (AMap: any, map: any, clearBuildPoints: number[][]) => {
    const building = new AMap.Buildings({
      zIndex: 10,
    })
    building.setStyle({
      hideWithoutStyle: false, // 是否隐藏设定区域外的楼块
      areas: [{
        visible: false, // 是否可见
        rejectTexture: false, // 是否屏蔽自定义地图的纹理
        color1: '00000000', // 楼顶颜色
        color2: '00000000', // 楼面颜色
        path: clearBuildPoints
      }]
    })
    map.add(building)
  }

  // 创建Three.js场景
  const createScene = (AMap: any, map: any) => {
    const customCoords = map.customCoords
    customCoordsRef.current = customCoords
    const centerPoint = map.getCenter()
    customCoords.setCenter([centerPoint.lng, centerPoint.lat])

    return new Promise((resolve, reject) => {
      const gllayer = new AMap.GLCustomLayer({
        zIndex: 110,
        init: async (gl: WebGLRenderingContext | WebGL2RenderingContext) => {
          // 检查 WebGL 支持
          if (!gl) {
            console.error('WebGL 不受支持')
            toast.error('WebGL 不受支持，无法加载3D场景')
            return
          }

          // 创建Three.js渲染器，优先使用 WebGL2，降级到 WebGL1
          let renderer: THREE.WebGLRenderer
          try {
            // 检查WebGL版本并使用合适的上下文
            const canvas = gl.canvas
            let context = gl

            // 如果传入的是WebGL1上下文，尝试获取WebGL2上下文
            if (gl.constructor.name === 'WebGLRenderingContext') {
              const webgl2Context = canvas.getContext('webgl2', {
                antialias: true,
                alpha: true,
                premultipliedAlpha: false
              })
              if (webgl2Context) {
                context = webgl2Context
                console.log('升级到 WebGL2 上下文')
              }
            }

            renderer = new THREE.WebGLRenderer({
              context: context,
              antialias: true,
              alpha: true,
              premultipliedAlpha: false
            })
            console.log('WebGL 渲染器创建成功')
          } catch (error) {
            console.warn('使用现有上下文创建渲染器失败，尝试备用方案:', error)
            try {
              // 备用方案：创建新的渲染器（不使用传入的上下文）
              const canvas = document.createElement('canvas')
              canvas.style.position = 'absolute'
              canvas.style.top = '0'
              canvas.style.left = '0'
              canvas.style.pointerEvents = 'none'
              gl.canvas.parentElement?.appendChild(canvas)

              renderer = new THREE.WebGLRenderer({
                canvas: canvas,
                antialias: true,
                alpha: true
              })
              console.log('使用备用Canvas创建渲染器成功')
              toast.info('使用兼容模式初始化3D渲染器')
            } catch (fallbackError) {
              console.error('无法创建 WebGL 渲染器:', fallbackError)
              toast.error('您的浏览器不支持 WebGL，无法显示3D场景')
              reject(fallbackError)
              return
            }
          }
          renderer.autoClear = false
          renderer.shadowMap.enabled = true
          renderer.shadowMap.type = THREE.PCFSoftShadowMap
          rendererRef.current = renderer

          // 创建相机
          const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 100, 1 << 30)
          cameraRef.current = camera

          // 设置场景
          const scene = sceneRef.current
          scene.background = null // 透明背景

          // 添加光照
          const ambientLight = new THREE.AmbientLight(0x404040, 0.6)
          scene.add(ambientLight)

          const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
          directionalLight.position.set(100, 100, 50)
          directionalLight.castShadow = true
          directionalLight.shadow.mapSize.width = 2048
          directionalLight.shadow.mapSize.height = 2048
          scene.add(directionalLight)

          // 添加楼层组
          scene.add(floorGroupRef.current)

          // 如果有SVG模型URL，加载模型
          if (svgModelUrl) {
            loadSVGModel(svgModelUrl)
          }

          resolve(true)
        },
        render: () => {
          if (!rendererRef.current || !cameraRef.current || !customCoordsRef.current) return

          const renderer = rendererRef.current
          const camera = cameraRef.current
          const scene = sceneRef.current
          const customCoords = customCoordsRef.current

          // 重新设置图层的渲染中心点
          const center = mapRef.current.getCenter()
          customCoords.setCenter([center.lng, center.lat])

          const { near, far, fov, up, lookAt, position } = customCoords.getCameraParams()

          // 这里的顺序不能颠倒，否则可能会出现绘制卡顿的效果
          camera.near = near
          camera.far = far
          camera.fov = fov
          camera.position.set(...position)
          camera.up.set(...up)
          camera.lookAt(...lookAt)
          camera.updateProjectionMatrix()

          renderer.render(scene, camera)

          // 这里必须执行！！重新设置 three 的 gl 上下文状态
          renderer.resetState()
        },
      })

      map.add(gllayer)
    })
  }

  // SVG加载器
  const loadSVG = (url: string): Promise<any> => {
    const svgLoader = new SVGLoader()
    return new Promise((resolve, reject) => {
      // 添加超时和错误处理
      const timeoutId = setTimeout(() => {
        reject(new Error(`SVG加载超时: ${url}`))
      }, 10000)

      svgLoader.load(
        url,
        (data: any) => {
          clearTimeout(timeoutId)
          resolve(data)
        },
        (progress: any) => {
          console.log('SVG加载进度:', progress)
        },
        (error: any) => {
          clearTimeout(timeoutId)
          console.error('SVG加载失败:', error)
          reject(new Error(`SVG加载失败: ${error.message || error}`))
        }
      )
    })
  }

  // 路径挤压为模型
  const paths2Mesh = (shape: THREE.Shape | THREE.Shape[], name: string): THREE.Mesh => {
    const getRandomInt = (min: number, max: number) => {
      return Math.floor(Math.random() * (max - min + 1)) + min
    }

    const extrudeSettings = {
      depth: name === 'floor' ? 8 : getRandomInt(6, 60),
    }

    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings)

    // 创建材质
    const material = new THREE.MeshLambertMaterial({
      color: name === 'floor' ? 0x8cc8ff : 0x00ff00,
      side: THREE.DoubleSide,
      transparent: true,
      opacity: 0.8
    })

    const mesh = new THREE.Mesh(geometry, material)

    if (name === 'floor') {
      mesh.receiveShadow = true
    } else {
      mesh.castShadow = true
    }

    mesh.name = name

    return mesh
  }

  // SVG转3D模型
  const getSVG2Model = async (url: string): Promise<THREE.Group> => {
    const svgPaths = await loadSVG(url) as { paths: any[] }

    const floorGroup = new THREE.Group()
    for (const path of svgPaths.paths) {
      const shapes = SVGLoader.createShapes(path)

      for (const shape of shapes) {
        const mesh = paths2Mesh(shape, path.userData?.node?.id || 'building')
        floorGroup.add(mesh)
      }
    }

    return floorGroup
  }

  // 加载SVG模型
  const loadSVGModel = useCallback(async (url: string) => {
    if (!url) return

    try {
      // 检查SVG文件是否存在
      const response = await fetch(url, { method: 'HEAD' })
      if (!response.ok) {
        console.warn(`SVG文件不存在: ${url}，跳过模型加载`)
        toast.info('未找到3D模型文件，使用基础地图模式')
        return
      }

      const floorGroup = await getSVG2Model(url)

      // 清除之前的模型
      floorGroupRef.current.clear()
      floorGroupRef.current.add(floorGroup)

      // 更新模型子对象引用
      floorGroupChildrenRef.current = [...floorGroup.children]

      setModelLoaded(true)
      toast.success('模型加载完成')

    } catch (error) {
      console.error('SVG模型加载失败:', error)
      // 不显示错误提示，因为SVG文件缺失是正常情况
      console.info('继续使用基础地图功能')
    }
  }, [])

  // 世界坐标转屏幕坐标
  const getViewCp = (v3: THREE.Vector3, v2: THREE.Vector2, camera: THREE.Camera) => {
    const worldVector = v3.clone()
    const standardVector = worldVector.project(camera) // 世界坐标转标准设备坐标
    const a = window.innerWidth / 2
    const b = window.innerHeight / 2
    const vx = Math.round(standardVector.x * a + a) // 标准设备坐标转屏幕坐标
    const vy = Math.round(-standardVector.y * b + b) // 标准设备坐标转屏幕坐标
    const p = new THREE.Vector2(vx, vy)

    v2.copy(p)
    return p
  }

  // 屏幕坐标转经纬度
  const coordsToLngLats = (point: THREE.Vector2, AMap: any, map: any, targetV2?: THREE.Vector2) => {
    const { x, y } = point
    const pixel = new AMap.Pixel(x, y)
    const lnglat = map.containerToLngLat(pixel)
    const v2 = new THREE.Vector2()
    v2.set(lnglat.lng, lnglat.lat)
    if (targetV2?.isVector2) {
      targetV2.copy(v2)
    }
    return v2
  }

  // 处理地图点击事件
  const handleMapClick = useCallback((e: any) => {
    try {
      console.log('🎯 地图点击事件触发:', e.lnglat.lng, e.lnglat.lat)
      console.log('📍 事件详情:', e)
      const lnglat: [number, number] = [e.lnglat.lng, e.lnglat.lat]

      // 射线检测Three.js对象（如果3D场景可用）
      const rayState = rayStateRef.current
      const camera = cameraRef.current

      console.log('🔍 检查3D组件状态:', { hasCamera: !!camera, hasRayState: !!rayState })

      if (camera && rayState) {
        console.log('🎮 尝试3D射线检测...')
        try {
          const mouse = rayState.mouse.clone()
          // 高德地图点击事件与3d模型的转换
          mouse.x = (e.originEvent.clientX / window.innerWidth) * 2 - 1
          mouse.y = -(e.originEvent.clientY / window.innerHeight) * 2 + 1

          rayState.raycaster.setFromCamera(mouse, camera)
          const rallyList: THREE.Intersection<THREE.Object3D<any>>[] = rayState.raycaster.intersectObjects(floorGroupChildrenRef.current)

          if (rallyList?.[0] && rallyList[0].object) {
            console.log('🏢 点击到3D模型:', rallyList[0].object.name)
            console.log('📍 模型世界坐标:', rallyList[0]?.point)

            const viewPoint = new THREE.Vector2() // 屏幕坐标
            getViewCp(rallyList[0]?.point!, viewPoint, camera)

            const lnglat = new THREE.Vector2()
            coordsToLngLats(viewPoint, AMapRef.current, mapRef.current, lnglat)

            const mesh = rallyList[0].object
            if (mesh.name !== 'floor') {
              // 点击在建筑上，用于绑定科室
              toast.success('点击在建筑上 - 可绑定科室')
              onModelClick?.(mesh, rallyList[0].point!)
            } else {
              // 点击在地板上，用于绑定设施
              toast.success('点击在地板上 - 可绑定设施')
              onModelClick?.(mesh, rallyList[0].point!)
            }

            // 3D模型点击处理完成，不再执行地图点击
            if (mapRef.current?.render) {
              mapRef.current.render()
            }
            return
          } else {
            console.log('🎮 3D射线检测未命中任何对象，继续处理地图点击')
          }
        } catch (error) {
          console.warn('3D射线检测失败，回退到地图点击:', error)
        }
      } else {
        console.log('⚠️ 3D摄像机未就绪，直接处理地图点击')
      }

      // 没有点击到3D模型，或3D场景不可用，处理普通地图点击
      console.log('🗺️ 处理地图点击:', lnglat)
      console.log('📞 onMapClick 回调函数存在:', !!onMapClick)
      console.log('🔍 onMapClick 函数详情:', onMapClick?.toString().substring(0, 100))

      if (onMapClick) {
        console.log('✅ 调用 onMapClick 回调...')
        try {
          onMapClick(lnglat)
          console.log('✅ onMapClick 调用完成')
        } catch (error) {
          console.error('❌ onMapClick 调用失败:', error)
        }
      } else {
        console.warn('❌ onMapClick 回调函数不存在!')
      }

      toast.success('点击在地图上')

      if (mapRef.current?.render) {
        mapRef.current.render()
      }
    } catch (error) {
      console.error('❌ handleMapClick 执行出错:', error)
      toast.error('地图点击处理失败')
    }
  }, [onMapClick, onModelClick])


  // 创建地图
  const createMap = async () => {
    if (!containerRef.current) {
      throw new Error('地图容器DOM元素不存在')
    }

    if (!AMapRef.current) {
      throw new Error('高德地图SDK未加载')
    }

    try {
      const AMap = AMapRef.current
      console.log('开始创建地图实例...', { center, zoom })

      // 创建地图
      const map = new AMap.Map(containerRef.current, {
        resizeEnable: true,
        center: center,
        zoom: zoom,
        viewMode: config.map.viewMode,
        buildingAnimation: true,
        pitch: config.map.pitch,
        rotation: config.map.rotation,
        features: config.map.features,
        mapStyle: config.map.style,
        showIndoorMap: false,
        showBuildingBlock: true, // 确保显示3D建筑
        skyColor: '#ffffff', // 天空颜色
        zIndex: 9
      })

      if (!map) {
        throw new Error('地图实例创建失败')
      }

      mapRef.current = map
      console.log('地图实例创建成功')

      // 尝试创建Loca容器（可选，失败不影响基础地图功能）
      try {
        if (window.Loca && window.Loca.Container) {
          const loca = new window.Loca.Container({
            map,
            zIndex: 9
          })
          locaRef.current = loca
          console.log('Loca 3D容器创建成功')
        } else {
          console.warn('Loca 3D可视化库不可用，跳过创建')
        }
      } catch (locaError) {
        console.warn('Loca容器创建失败，使用基础地图功能:', locaError)
      }

      // 绑定地图点击事件
      console.log('🔗 正在绑定地图点击事件...')
      map.on('click', handleMapClick)
      console.log('✅ 地图点击事件绑定成功')

      // 等待地图完全加载
      return new Promise<void>((resolve, reject) => {
        map.on('complete', () => {
          console.log('地图加载完成事件触发')
          setMapLoaded(true)

          // 异步创建Three.js场景（不阻塞地图使用）
          createScene(AMap, map).then(() => {
            console.log('Three.js场景创建完成')
            toast.success('地图和3D场景初始化完成')
            resolve()
          }).catch((sceneError) => {
            console.warn('Three.js场景创建失败，但地图功能正常:', sceneError)
            toast.success('地图初始化完成（3D场景加载失败）')
            resolve() // 仍然算作成功，因为基础地图功能正常
          })
        })

        // 设置超时保护
        setTimeout(() => {
          if (!mapLoaded) {
            console.warn('地图加载超时，强制设为已加载')
            setMapLoaded(true)
            toast.success('地图初始化完成（部分功能可能不可用）')
            resolve()
          }
        }, 10000) // 10秒超时
      })

    } catch (error) {
      console.error('地图创建过程中发生错误:', error)
      const errorMessage = error instanceof Error ? error.message : '地图创建失败'
      throw new Error(`地图创建失败: ${errorMessage}`)
    }
  }

  // 初始化
  useEffect(() => {
    let mounted = true
    const hasAMapDom = () => {
      if (!containerRef.current) return false
      // 检查容器内是否已有高德地图相关DOM（避免误报）
      return !!containerRef.current.querySelector('[class*="amap-"]')
    }

    const initMap = async () => {
      try {
        if (initOnceRef.current) {
          // 避免 React 18 开发模式双调用导致的重复初始化
          console.log('地图已初始化，跳过二次初始化')
          return
        }
        console.log('开始初始化地图...', {
          amapKey: amapKey ? amapKey.substring(0, 8) + '...' : 'undefined',
          AMAP_KEY: AMAP_KEY ? AMAP_KEY.substring(0, 8) + '...' : 'undefined',
          containerRef: !!containerRef.current,
          center,
          zoom
        })

        // 检查必要的参数
        if (!amapKey && !AMAP_KEY) {
          throw new Error('缺少高德地图 API Key')
        }

        // 等待容器渲染完成且尺寸可用，最多重试20次
        let retryCount = 0
        const maxRetries = 20
        while (mounted) {
          const el = containerRef.current
          if (el && el.clientWidth > 0 && el.clientHeight > 0) break
          if (retryCount >= maxRetries) break
          console.log(`等待地图容器渲染/尺寸生效... (第${retryCount + 1}次)`, {
            hasEl: !!el,
            w: el?.clientWidth || 0,
            h: el?.clientHeight || 0
          })
          await new Promise(resolve => setTimeout(resolve, 200))
          retryCount++
        }

        if (!containerRef.current || containerRef.current.clientWidth === 0 || containerRef.current.clientHeight === 0) {
          // 若检测到已有AMap DOM，则视为已成功初始化，避免误报
          if (hasAMapDom()) {
            console.warn('容器尺寸未就绪，但检测到地图DOM，跳过错误并标记为已加载')
            setMapLoaded(true)
            setMapLoadFailed(false)
            initOnceRef.current = true
            return
          }
          throw new Error('地图容器初始化超时，请刷新页面重试')
        }

        // 确保组件还在挂载状态
        if (!mounted) return

        // 加载高德地图 SDK
        AMapRef.current = await CreateAMap()
        console.log('高德地图 SDK 加载成功')

        // 再次确保组件还在挂载状态
        if (!mounted) return

        // 创建地图实例
        if (containerRef.current) {
          await createMap()
          console.log('地图创建成功')
          initOnceRef.current = true
        } else {
          throw new Error('地图容器在SDK加载后丢失')
        }
      } catch (error) {
        console.error('地图初始化失败:', error)
        const errorMessage = error instanceof Error ? error.message : '未知错误'

        // 如果已经存在地图相关DOM，视为成功（多为开发模式下的重复加载误报）
        if (hasAMapDom()) {
          console.warn('检测到地图DOM已存在，忽略错误并标记为已加载:', errorMessage)
          setMapLoaded(true)
          setMapLoadFailed(false)
          initOnceRef.current = true
          return
        }

        // 显示具体的错误信息给用户
        if (errorMessage.includes('API Key无效') || errorMessage.includes('key')) {
          toast.error('地图API Key无效，请检查配置')
          setLoadError('API Key 配置错误')
          setMapLoadFailed(true)
        } else if (errorMessage.includes('网络') || errorMessage.includes('timeout') || errorMessage.includes('load')) {
          toast.error('网络连接失败，请检查网络后重试')
          setLoadError('网络连接失败')
          // 网络错误自动重试
          setTimeout(() => {
            toast.info('正在重试地图初始化...', { duration: 2000 })
            setMapLoadFailed(false)
            setLoadError('')
            initMap()
          }, 3000)
        } else if (errorMessage.includes('quota')) {
          toast.error('地图API调用量已超限，请稍后再试')
          setLoadError('API 调用量超限')
          setMapLoadFailed(true)
        } else {
          toast.error(`地图初始化失败: ${errorMessage}`)
          setLoadError(errorMessage)
          setMapLoadFailed(true)
        }

        // 设置错误状态，显示备用内容
        setMapLoaded(false)
      }
    }

    initMap()

    return () => {
      // 标记组件已卸载
      mounted = false

      // 清理资源
      clearLocationHighlight()
      if (mapRef.current) {
        mapRef.current.destroy()
      }
    }
  }, [])

  // 监听center和zoom变化，更新地图视图
  useEffect(() => {
    if (mapRef.current && mapLoaded) {
      console.log('=== 地图center/zoom变化 ===')
      console.log('新的中心点:', center)
      console.log('新的缩放级别:', zoom)
      console.log('当前地图实例:', mapRef.current)

      try {
        // 获取当前地图的中心点和缩放级别
        const currentCenter = mapRef.current.getCenter()
        const currentZoom = mapRef.current.getZoom()

        console.log('当前地图中心点:', [currentCenter.lng, currentCenter.lat])
        console.log('当前地图缩放级别:', currentZoom)

        // 检查是否需要更新
        const centerChanged = Math.abs(currentCenter.lng - center[0]) > 0.0001 ||
          Math.abs(currentCenter.lat - center[1]) > 0.0001
        const zoomChanged = Math.abs(currentZoom - zoom) > 0.1

        if (centerChanged || zoomChanged) {
          console.log('需要更新地图视图')

          // 使用更精确的方法更新地图，避免触发无限循环
          mapRef.current.setZoomAndCenter(zoom, center)

          // 同时更新自定义坐标系统的中心点
          if (customCoordsRef.current) {
            customCoordsRef.current.setCenter(center)
            console.log('已更新自定义坐标系统中心点')
          }

          // 创建位置高亮效果
          setTimeout(() => {
            createLocationHighlight(center)
          }, 500) // 延迟一点确保地图已经定位完成

          toast.success(`已定位到: ${center[1].toFixed(4)}, ${center[0].toFixed(4)}`)
        } else {
          console.log('地图视图无需更新')
        }
      } catch (error) {
        console.error('更新地图视图失败:', error)
        toast.error('地图定位更新失败')
      }
    } else {
      console.log('地图未准备就绪，跳过更新:', {
        hasMap: !!mapRef.current,
        mapLoaded
      })
    }
  }, [center, zoom, mapLoaded])

  // 加载SVG模型
  useEffect(() => {
    if (svgModelUrl && mapLoaded) {
      loadSVGModel(svgModelUrl)
    }
  }, [svgModelUrl, mapLoaded, loadSVGModel])

  // 监听外部传入的突发事件列表变化
  useEffect(() => {
    if (emergencies && emergencies.length > 0) {
      setActiveEmergencies(emergencies)
    }
  }, [emergencies])

  // 位置监控WebSocket连接
  useEffect(() => {
    if (!enableLocationMonitor) return

    let socket: any = null
    
    const connectWebSocket = async () => {
      try {
        // 动态导入socket.io-client
        const { io } = await import('socket.io-client')
        
        const token = await getValidToken()
        if (!token) {
          console.warn('未找到token，无法建立位置WebSocket连接')
          return
        }

        socket = io(`${apiBaseUrl}/ws/location`, {
          auth: { token },
          autoConnect: true,
          reconnection: true,
          reconnectionAttempts: 5,
          reconnectionDelay: 2000
        })

        socket.on('connect', () => {
          console.log('位置WebSocket连接成功')
          setIsLocationConnected(true)
          socket.emit('subscribe', { room: 'location-updates' })
          fetchUserLocations()
          fetchLocationRequests()
        })

        socket.on('disconnect', () => {
          console.log('位置WebSocket连接断开')
          setIsLocationConnected(false)
        })

        socket.on('location-changed', (data: any) => {
          console.log('收到位置更新:', data)
          
          if (data.action === 'update' && data.location) {
            handleUserLocationUpdate(data.location)
          } else if (data.action === 'offline' && data.userId) {
            handleUserOffline(data.userId)
          }
        })

        socket.on('location-request', (data: any) => {
          console.log('收到位置请求更新:', data)
          
          if (data.action === 'new' && data.request) {
            setLocationRequests(prev => [...prev, data.request])
            showLocationRequestNotification(data.request)
          } else if (data.action === 'update' && data.request) {
            setLocationRequests(prev =>
              prev.map(req => req.id === data.request.id ? data.request : req)
            )
          }
        })

      } catch (error) {
        console.error('位置WebSocket连接失败:', error)
      }
    }

    connectWebSocket()
    
    // 添加定时器定期获取位置数据（作为WebSocket的备份方案）
    const locationInterval = setInterval(() => {
      console.log('大屏端：定时获取位置数据')
      fetchUserLocations()
      fetchLocationRequests()
    }, 10000) // 每10秒获取一次

    // 初始获取一次数据
    setTimeout(() => {
      console.log('大屏端：初始获取位置数据')
      fetchUserLocations()
      fetchLocationRequests()
    }, 1000)

    return () => {
      if (socket) {
        socket.disconnect()
      }
      clearInterval(locationInterval)
    }
  }, [enableLocationMonitor, apiBaseUrl])

  // 专用：大屏端令牌键，避免与小程序/其它模块冲突
  const SCREEN_TOKEN_KEY = 'screen_admin_token'
  const SCREEN_REFRESH_KEY = 'screen_admin_refresh_token'

  // 一次性清除旧token（仅清理大屏端专用键，防止与小程序混用）
  const clearOldTokens = () => {
    const lastClearTime = localStorage.getItem('lastTokenClear')
    const currentTime = Date.now().toString()
    
    // 如果没有清除记录或超过1小时，清除token
    if (!lastClearTime || (Date.now() - parseInt(lastClearTime)) > 3600000) {
      console.log('大屏端：清除旧token（专用键）以防API混用问题')
      localStorage.removeItem(SCREEN_TOKEN_KEY)
      localStorage.removeItem(SCREEN_REFRESH_KEY)
      localStorage.setItem('lastTokenClear', currentTime)
    }
  }

  // 获取可用的后台管理token（过滤掉wxapp token与过期token）
  const getValidToken = async (): Promise<string | null> => {
    const readToken = () => localStorage.getItem(SCREEN_TOKEN_KEY)

    const isInvalid = (token: string) => {
      try {
        const payloadPart = token.split('.')[1]
        const payload = JSON.parse(atob(payloadPart.replace(/-/g, '+').replace(/_/g, '/')))
        const isWx = payload?.aud === 'wxapp'
        const isExpired = typeof payload?.exp === 'number' && Date.now() >= payload.exp * 1000
        return isWx || isExpired
      } catch {
        return true
      }
    }

    let token = readToken()
    if (!token || isInvalid(token)) {
      const loginOk = await autoLogin()
      if (!loginOk) return null
      token = readToken()
    }
    return token || null
  }

  // 自动登录获取token
  const autoLogin = async () => {
    try {
      const loginUrl = `${apiBaseUrl.replace('/v1', '')}/v1/auth/login`
      console.log('大屏端：尝试自动登录...', loginUrl)
      
      // 尝试多组演示账号，直到成功
      const demoCredentials = [
        { username: 'admin', password: 'admin123' },
        { username: 'jiangjiankai', password: 'jjk123456' },
        { username: 'guomengzhe', password: 'gmz123456' },
      ]

      for (const creds of demoCredentials) {
        const response = await fetch(loginUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(creds)
        })

        console.log('大屏端：登录响应状态:', response.status)

        if (response.ok) {
          const data = await response.json()
          console.log('大屏端：登录响应数据:', data)

          // 兼容多种返回格式
          const accessToken = (data && (
            data.accessToken ||
            data.access_token ||
            (data.data && data.data.accessToken) ||
            (data.tokens && data.tokens.accessToken)
          )) as string | undefined
          const refreshToken = (data && (
            data.refreshToken ||
            (data.data && data.data.refreshToken) ||
            (data.tokens && data.tokens.refreshToken)
          )) as string | undefined

          if (data.success && accessToken) {
            localStorage.setItem(SCREEN_TOKEN_KEY, accessToken)
            if (refreshToken) {
              localStorage.setItem(SCREEN_REFRESH_KEY, refreshToken)
            }
            console.log('大屏端：自动登录成功，token已保存')
            return true
          } else {
            console.error('大屏端：登录响应格式不正确:', data)
            // 尝试下一组凭证
          }
        } else {
          const errorText = await response.text()
          console.error('大屏端：登录请求失败:', response.status, errorText)
          // 仅当 5xx 时中断循环，其它继续尝试
          if (response.status >= 500) {
            return false
          }
        }
      }
      
      // 所有凭证都失败
      return false
    } catch (error) {
      console.error('大屏端：自动登录出错:', error)
      return false
    }
  }

  // 获取用户位置数据
  const fetchUserLocations = async () => {
    try {
      // 首次运行时清除旧token
      clearOldTokens()
      
      const token = await getValidToken()
      if (!token) {
        console.log('大屏端：自动登录失败，无法获取位置数据')
        return
      }

      console.log('大屏端：正在获取用户位置数据...', `${apiBaseUrl}/location/users?online=true`)
      
      const response = await fetch(`${apiBaseUrl}/location/users?online=true`, {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      })

      console.log('大屏端：位置数据响应状态:', response.status)

      if (response.ok) {
        const data = await response.json()
        console.log('大屏端：获取到的位置数据:', data)
        
        if (data.success && data.data.locations) {
          // 去重：同一用户仅保留最新一条
          const latestByUser = new Map<string, UserLocation>()
          ;(data.data.locations as UserLocation[]).forEach((loc) => {
            const exists = latestByUser.get(loc.userId)
            if (!exists || (loc.timestamp || 0) > (exists.timestamp || 0)) {
              latestByUser.set(loc.userId, loc)
            }
          })
          const uniqueLocations = Array.from(latestByUser.values())

          setUserLocations(uniqueLocations)
          console.log(`大屏端：更新位置数据（去重后），共${uniqueLocations.length}个在线用户`)
          
          // 在地图上显示所有用户位置（仅最新）
          uniqueLocations.forEach((location: UserLocation) => {
            addUserLocationToMap(location)
          })

          // 首次拿到位置后，自动飞到第一个在线用户位置，避免默认中心看不到
          if (!hasCenteredOnLocationsRef.current && mapRef.current && AMapRef.current && data.data.locations.length > 0) {
            const first = data.data.locations[0]
            try {
              const target: [number, number] = [first.longitude, first.latitude]
              mapRef.current.setZoomAndCenter(18, target)
              if (customCoordsRef.current) {
                customCoordsRef.current.setCenter(target)
              }
              hasCenteredOnLocationsRef.current = true
              console.log('大屏端：已自动定位到首个在线用户位置', target)
            } catch (e) {
              console.warn('大屏端：自动定位到用户位置失败', e)
            }
          }
        } else {
          console.log('大屏端：位置数据格式不正确或为空:', data)
        }
      } else {
        const errorText = await response.text()
        console.error('大屏端：获取位置数据失败:', response.status, errorText)
        // 401/403 触发一次性重登并重试
        if (response.status === 401 || response.status === 403) {
          localStorage.removeItem('screen_admin_token')
          localStorage.removeItem('screen_admin_refresh_token')
          const relogin = await autoLogin()
          if (relogin) {
            const newToken = await getValidToken()
            if (!newToken) return
            const retry = await fetch(`${apiBaseUrl}/location/users?online=true`, {
              headers: {
                'Authorization': `Bearer ${newToken}`,
                'Content-Type': 'application/json'
              }
            })
            if (retry.ok) {
              const data = await retry.json()
              if (data.success && data.data.locations) {
                const latestByUser = new Map<string, UserLocation>()
                ;(data.data.locations as UserLocation[]).forEach((loc: UserLocation) => {
                  const exists = latestByUser.get(loc.userId)
                  if (!exists || (loc.timestamp || 0) > (exists.timestamp || 0)) {
                    latestByUser.set(loc.userId, loc)
                  }
                })
                const uniqueLocations = Array.from(latestByUser.values())
                setUserLocations(uniqueLocations)
                uniqueLocations.forEach((location: UserLocation) => addUserLocationToMap(location))
              }
            }
          }
        }
      }
    } catch (error) {
      console.error('大屏端：获取用户位置失败:', error)
    }
  }

  // 获取位置请求数据
  const fetchLocationRequests = async () => {
    try {
      const token = await getValidToken()
      if (!token) return

      const response = await fetch(`${apiBaseUrl}/location/requests?status=pending&status=responding`, {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      })

      if (response.ok) {
        const data = await response.json()
        if (data.success && data.data.requests) {
          setLocationRequests(data.data.requests)
        }
      } else if (response.status === 401 || response.status === 403) {
        localStorage.removeItem('screen_admin_token')
        localStorage.removeItem('screen_admin_refresh_token')
        const relogin = await autoLogin()
        if (relogin) {
          const newToken = await getValidToken()
          if (!newToken) return
          const retry = await fetch(`${apiBaseUrl}/location/requests?status=pending&status=responding`, {
            headers: {
              'Authorization': `Bearer ${newToken}`,
              'Content-Type': 'application/json'
            }
          })
          if (retry.ok) {
            const data = await retry.json()
            if (data.success && data.data.requests) {
              setLocationRequests(data.data.requests)
            }
          }
        }
      }
    } catch (error) {
      console.error('获取位置请求失败:', error)
    }
  }

  // 处理用户位置更新
  const handleUserLocationUpdate = (location: UserLocation) => {
    // 仅保留最新一条
    setUserLocations(prev => {
      const filtered = prev.filter(loc => loc.userId !== location.userId)
      return [...filtered, location]
    })
    addUserLocationToMap(location)
  }

  // 处理用户下线
  const handleUserOffline = (userId: string) => {
    setUserLocations(prev => prev.filter(loc => loc.userId !== userId))
    removeUserLocationFromMap(userId)
  }

  // 在地图上添加用户位置
  const addUserLocationToMap = (location: UserLocation) => {
    const userPOI: POIData = {
      id: `user_${location.userId}`,
      name: location.username || `用户${location.userId.slice(-4)}`,
      type: 'user',
      position: [location.longitude, location.latitude],
      floor: location.floor || 'L1',
      description: `${location.department || '访客'} - 精度: ${location.accuracy}m`,
      metadata: {
        userId: location.userId,
        accuracy: location.accuracy,
        deviceType: location.deviceType,
        lastUpdate: location.lastUpdate,
        isUserLocation: true
      }
    }

    // 基于最新状态原子更新，避免闭包读到过期的 internalPOIs 导致重复
    setInternalPOIs(prev => {
      const index = prev.findIndex(poi => poi.id === userPOI.id)
      if (index >= 0) {
        const next = [...prev]
        next[index] = userPOI
        return next
      }
      return [...prev, userPOI]
    })
  }

  // 从地图上移除用户位置
  const removeUserLocationFromMap = (userId: string) => {
    setInternalPOIs(prev => prev.filter(poi => poi.id !== `user_${userId}`))
  }

  // 显示位置请求通知
  const showLocationRequestNotification = (request: LocationRequest) => {
    const isUrgent = request.priority === 'critical' || request.priority === 'high'
    
    if (isUrgent) {
      toast.error(`紧急求助: ${request.title}`, {
        description: `来自用户: ${request.username}`,
        duration: 10000
      })
    } else {
      toast.info(`新的位置请求: ${request.title}`, {
        description: `来自用户: ${request.username}`,
        duration: 5000
      })
    }
    
    // 如果有回调函数，调用它
    if (onLocationRequestClick) {
      onLocationRequestClick(request)
    }
  }

  // 处理突发事件
  const handleEmergencyClick = useCallback((emergency: EmergencyEvent) => {
    setSelectedEmergency(emergency)
    if (onEmergencyClick) {
      onEmergencyClick(emergency)
    }

    // 飞行到突发事件位置
    if (mapRef.current && AMapRef.current) {
      const [lng, lat] = emergency.location.coordinates
      const position = new AMapRef.current.LngLat(lng, lat)
      mapRef.current.setCenter(position)
      mapRef.current.setZoom(18) // 放大到更详细的级别

      // 创建高亮效果
      createLocationHighlight(emergency.location.coordinates)
    }
  }, [onEmergencyClick, createLocationHighlight])

  // 对外暴露的方法
  const viewerMethods = {
    addPOI: (poi: POIData) => {
      setInternalPOIs(prev => [...prev, poi])
      // 标记渲染由useEffect自动处理
    },
    removePOI: (poiId: string) => {
      setInternalPOIs(prev => prev.filter(p => p.id !== poiId))
      // 标记移除由useEffect自动处理
    },
    addStore: (store: StoreData) => {
      setStores(prev => [...prev, store])
      // 标记渲染由useEffect自动处理
    },
    removeStore: (storeId: string) => {
      setStores(prev => prev.filter(s => s.id !== storeId))
      // 标记移除由useEffect自动处理
    },
    clearAllPOIs: () => {
      setInternalPOIs([])
      setStores([])
      // 标记清除由useEffect自动处理
    },
    flyTo: (lngLat: [number, number], zoom?: number) => {
      if (mapRef.current) {
        console.log('flyTo调用:', { lngLat, zoom })

        try {
          // 先清除之前的高亮效果
          clearLocationHighlight()

          // 使用更强制的方法设置位置
          const targetZoom = zoom || mapRef.current.getZoom()
          mapRef.current.setZoomAndCenter(targetZoom, lngLat)

          // 更新自定义坐标系统
          if (customCoordsRef.current) {
            customCoordsRef.current.setCenter(lngLat)
          }

          // 延迟添加位置高亮效果，确保地图已经定位完成
          setTimeout(() => {
            createLocationHighlight(lngLat)
          }, 600)

          console.log('flyTo执行完成')
          return true
        } catch (error) {
          console.error('flyTo执行失败:', error)
          return false
        }
      }
      return false
    },
    clearSelectedPOI: () => {
      setSelectedPOI(null)
      console.log('已清除选中的POI')
    },
    clearHighlight: () => {
      clearLocationHighlight()
      console.log('已清除地图高亮效果')
    },
    loadModel: loadSVGModel,
    getMap: () => mapRef.current,
    getScene: () => sceneRef.current,
    getCamera: () => cameraRef.current,
    // 突发事件相关方法
    addEmergency: (emergency: EmergencyEvent) => {
      setActiveEmergencies(prev => {
        // 如果已存在相同ID的事件，则更新它
        const exists = prev.some(e => e.id === emergency.id)
        if (exists) {
          return prev.map(e => e.id === emergency.id ? emergency : e)
        }
        // 否则添加新事件
        return [...prev, emergency]
      })

      // 如果是严重事件，自动飞行到事件位置
      if (emergency.severity === 'critical' || emergency.severity === 'high') {
        if (mapRef.current && AMapRef.current) {
          const [lng, lat] = emergency.location.coordinates
          const position = new AMapRef.current.LngLat(lng, lat)
          mapRef.current.setCenter(position)
          mapRef.current.setZoom(18)

          // 创建高亮效果
          createLocationHighlight(emergency.location.coordinates)

          // 显示提示
          toast.error(`紧急事件: ${emergency.title}`, {
            description: emergency.description,
            duration: 5000
          })
        }
      }

      return true
    },
    removeEmergency: (id: string) => {
      setActiveEmergencies(prev => prev.filter(e => e.id !== id))

      // 如果当前选中的是被移除的事件，清除选择
      if (selectedEmergency && selectedEmergency.id === id) {
        setSelectedEmergency(null)
      }

      return true
    },
    highlightEmergency: (id: string) => {
      const emergency = activeEmergencies.find(e => e.id === id)
      if (emergency) {
        handleEmergencyClick(emergency)
        return true
      }
      return false
    },
    // 位置监控相关方法
    addUserLocation: (location: UserLocation) => {
      handleUserLocationUpdate(location)
    },
    removeUserLocation: (userId: string) => {
      handleUserOffline(userId)
    },
    getUserLocations: () => userLocations,
    getLocationRequests: () => locationRequests,
    updateRequestStatus: async (requestId: string, status: string) => {
      try {
        const token = localStorage.getItem('token')
        if (!token) return

        const response = await fetch(`${apiBaseUrl}/v1/location/requests/${requestId}`, {
          method: 'PUT',
          headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ status })
        })

        if (response.ok) {
          fetchLocationRequests() // 刷新请求列表
        }
      } catch (error) {
        console.error('更新请求状态失败:', error)
      }
    }
  }

  // 将方法暴露给父组件
  React.useImperativeHandle(ref, () => viewerMethods)

  // 渲染突发事件标记
  useEffect(() => {
    if (!sceneRef.current || activeEmergencies.length === 0) return

    // 清除之前的突发事件标记
    const existingMarkers = sceneRef.current.children.filter(
      child => child.name && child.name.startsWith('emergency-')
    )
    existingMarkers.forEach(marker => sceneRef.current.remove(marker))

    // 添加新的突发事件标记
    activeEmergencies.forEach(emergency => {
      // 使用EmergencyMarker组件渲染标记
      const marker = document.createElement('div')
      const root = ReactDOM.createRoot(marker)
      root.render(
        <EmergencyMarker
          emergency={emergency}
          scene={sceneRef.current}
          onMarkerClick={handleEmergencyClick}
        />
      )
    })
  }, [activeEmergencies, handleEmergencyClick])

  return (
    <div className={className}>
      <div
        id="container"
        ref={containerRef}
        className="w-full h-full relative"
        style={{ minHeight: '400px' }}
      >

        {mapLoadFailed && (
          <div className="absolute inset-0 flex items-center justify-center bg-gray-50">
            <div className="text-center p-6">
              <div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
                <span className="text-red-500 text-2xl">⚠️</span>
              </div>
              <h3 className="text-lg font-semibold text-gray-900 mb-2">地图加载失败</h3>
              <p className="text-gray-600 mb-4">{loadError || '地图服务暂时不可用'}</p>
              <button
                onClick={() => {
                  setMapLoadFailed(false)
                  setLoadError('')
                  // 重新初始化地图
                  window.location.reload()
                }}
                className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
              >
                重新加载
              </button>
              <div className="mt-4 p-4 bg-blue-50 rounded-lg">
                <p className="text-sm text-blue-700">
                  💡 建议检查：网络连接、API Key配置、服务器状态
                </p>
              </div>
            </div>
          </div>
        )}



        {/* POI信息面板 */}
        {selectedPOI && (
          <div className="absolute top-20 left-4 bg-black/70 backdrop-blur-md border border-white/10 text-white rounded-lg shadow-lg p-4 max-w-sm z-50">
            <div className="flex justify-between items-start mb-2">
              <h3 className="font-semibold text-lg text-white">{selectedPOI.name}</h3>
              <button
                onClick={() => setSelectedPOI(null)}
                className="text-white/60 hover:text-white text-xl"
              >
                ×
              </button>
            </div>
            <p className="text-sm text-white/70 mb-1">类型: {selectedPOI.type}</p>
            <p className="text-sm text-white/70 mb-1">楼层: {selectedPOI.floor}</p>
            {selectedPOI.description && (
              <p className="text-sm text-white/80">{selectedPOI.description}</p>
            )}
          </div>
        )}

        {/* 突发事件信息面板 */}
        {selectedEmergency && (
          <div className="absolute top-20 right-4 bg-white rounded-lg shadow-lg p-4 max-w-sm z-50 border-l-4"
            style={{ borderColor: selectedEmergency.visualEffect?.color || '#FF0000' }}>
            <div className="flex justify-between items-start mb-2">
              <h3 className="font-semibold text-lg flex items-center">
                <span className="inline-block w-3 h-3 rounded-full mr-2"
                  style={{ backgroundColor: selectedEmergency.visualEffect?.color || '#FF0000' }}></span>
                {selectedEmergency.title}
              </h3>
              <button
                onClick={() => setSelectedEmergency(null)}
                className="text-gray-500 hover:text-gray-700 text-xl"
              >
                ×
              </button>
            </div>
            <div className="space-y-2">
              <p className="text-sm text-gray-700">{selectedEmergency.description}</p>
              <div className="flex justify-between text-xs text-gray-500">
                <span>位置: {selectedEmergency.location.name}</span>
                <span>楼层: {selectedEmergency.location.floor}</span>
              </div>
              <div className="flex justify-between text-xs">
                <span className={`px-2 py-1 rounded ${selectedEmergency.severity === 'critical' ? 'bg-red-100 text-red-800' :
                    selectedEmergency.severity === 'high' ? 'bg-orange-100 text-orange-800' :
                      selectedEmergency.severity === 'medium' ? 'bg-yellow-100 text-yellow-800' :
                        'bg-blue-100 text-blue-800'
                  }`}>
                  {selectedEmergency.severity === 'critical' ? '危急' :
                    selectedEmergency.severity === 'high' ? '高危' :
                      selectedEmergency.severity === 'medium' ? '中度' : '低危'}
                </span>
                <span className={`px-2 py-1 rounded ${selectedEmergency.status === 'active' ? 'bg-red-100 text-red-800' :
                    selectedEmergency.status === 'responding' ? 'bg-blue-100 text-blue-800' :
                      selectedEmergency.status === 'contained' ? 'bg-green-100 text-green-800' :
                        'bg-gray-100 text-gray-800'
                  }`}>
                  {selectedEmergency.status === 'active' ? '活跃' :
                    selectedEmergency.status === 'responding' ? '响应中' :
                      selectedEmergency.status === 'contained' ? '已控制' : '已解决'}
                </span>
              </div>
              {selectedEmergency.evacuationRequired && (
                <div className="bg-red-100 text-red-800 p-2 rounded text-sm font-medium">
                  需要疏散
                </div>
              )}
              {selectedEmergency.updates && selectedEmergency.updates.length > 0 && (
                <div className="mt-2 pt-2 border-t border-gray-200">
                  <h4 className="text-sm font-medium mb-1">最新进展</h4>
                  <p className="text-xs text-gray-700">
                    {selectedEmergency.updates[selectedEmergency.updates.length - 1].content}
                  </p>
                </div>
              )}
            </div>
          </div>
        )}


        {/* 错误状态显示 */}
        {mapLoadFailed && (
          <div className="absolute inset-0 flex items-center justify-center bg-red-50 z-20">
            <div className="text-center p-6">
              <div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
                <svg className="w-8 h-8 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
                </svg>
              </div>
              <h3 className="text-lg font-medium text-red-900 mb-2">地图加载失败</h3>
              <p className="text-sm text-red-700 mb-4">
                {loadError || '未知错误'}
              </p>
              <div className="space-x-2">
                <button
                  onClick={() => {
                    setMapLoadFailed(false)
                    setLoadError('')
                    window.location.reload()
                  }}
                  className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors"
                >
                  重新加载
                </button>
                <button
                  onClick={() => setMapLoadFailed(false)}
                  className="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400 transition-colors"
                >
                  隐藏错误
                </button>
              </div>
            </div>
          </div>
        )}

        {/* 状态指示器 */}
        <div className="absolute bottom-4 left-4 bg-white/90 rounded px-3 py-2 text-sm z-10">
          <div className="flex items-center gap-2">
            <div className={`w-2 h-2 rounded-full ${mapLoaded ? 'bg-green-500' : 'bg-yellow-500'}`}></div>
            <span>地图</span>
            <div className={`w-2 h-2 rounded-full ${modelLoaded ? 'bg-green-500' : 'bg-gray-300'}`}></div>
            <span>模型</span>
            {enableLocationMonitor && (
              <>
                <div className={`w-2 h-2 rounded-full ${isLocationConnected ? 'bg-green-500' : 'bg-red-500'}`}></div>
                <span>位置</span>
              </>
            )}
          </div>
        </div>

        {/* 位置监控统计面板已隐藏，但保留地图标记功能 */}
        {false && enableLocationMonitor && (
          <div className="absolute top-4 right-4 bg-white/95 rounded-lg shadow-lg p-4 min-w-64 z-10">
            <h3 className="font-semibold mb-3 text-gray-800">实时位置监控</h3>
            <div className="grid grid-cols-2 gap-4 text-sm">
              <div>
                <div className="text-2xl font-bold text-blue-600">{userLocations.length}</div>
                <div className="text-gray-600">在线用户</div>
              </div>
              <div>
                <div className="text-2xl font-bold text-orange-600">
                  {locationRequests.filter(r => r.status === 'pending').length}
                </div>
                <div className="text-gray-600">待处理请求</div>
              </div>
              <div>
                <div className="text-2xl font-bold text-red-600">
                  {locationRequests.filter(r => r.priority === 'critical' || r.priority === 'high').length}
                </div>
                <div className="text-gray-600">紧急求助</div>
              </div>
              <div>
                <div className="text-2xl font-bold text-green-600">
                  {locationRequests.filter(r => r.status === 'responding').length}
                </div>
                <div className="text-gray-600">响应中</div>
              </div>
            </div>
            
            {/* 连接状态 */}
            <div className="mt-3 pt-3 border-t border-gray-200">
              <div className="flex items-center gap-2 text-xs">
                <div className={`w-2 h-2 rounded-full ${isLocationConnected ? 'bg-green-500' : 'bg-red-500'}`}></div>
                <span className={isLocationConnected ? 'text-green-600' : 'text-red-600'}>
                  {isLocationConnected ? '实时连接正常' : '连接断开'}
                </span>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  )
})

HospitalMapViewer.displayName = 'HospitalMapViewer'

export type { POIData, StoreData, HospitalMapViewerProps, HospitalMapViewerRef }